var Snake = require('./Snake');
/**
 *
 * @constructor
 */
function Grid(span, callback) {
  this.span = span || 50;
  this.callback = callback;
  this.snakes = [];
  this.run();
}

Grid.prototype.randomWarm = function () {
  var warm = this.getSnake('warm');
  if (!warm || warm.status !== 'fixed') {
    var lifeBook = {};
    this.snakes.forEach(function (snake) {
      snake.data.forEach(function (pos) {
        lifeBook[pos.x + '' + pos.y] = snake.id;
      });
    });
    while (true) {
      var x = Math.floor(Math.random() * this.span), y = Math.floor(Math.random() * this.span);
      if (!lifeBook[x + '' + y]) {
        this.snakes.push(new Snake('warm').setProp({
          status: 'fixed',
          type: Math.random() > 0.5 ? 'mushroom' : '',
          data: [{x: x, y: y}]
        }));
        break;
      }
    }
  }
  return this;
}

Grid.prototype.run = function () {
  var me = this, warm;
  this.intervalId = setInterval(function () {
    var hasWarm = me.hasSnake();
    me.clearDeadSnake().randomWarm();
    warm = me.getSnake('warm');
    me.snakes.forEach(function (snake) {
      snake.nextStep(warm);
    });
    me.check();
    if (hasWarm) {
      me.callback(me);
    }
  }, 200);
  return this;
}

Grid.prototype.deadSnakes = function () {
  return this.snakes.filter(function (snake) {
    return snake.status === false && snake.id !== 'warm';
  });
}

Grid.prototype.reviveSnakes = function () {
  return this.snakes.filter(function (snake) {
    return snake.revive && snake.id !== 'warm';
  });
}

Grid.prototype.hasSnake = function () {
  return this.snakes.some(function (snake) {
    return snake.id !== 'warm';
  });
}

Grid.prototype.stop = function () {
  clearInterval(this.intervalId);
  this.intervalId = 0;
}

Grid.prototype.push = function (id, revive) {
  var posX = Math.floor(Math.random() * this.span), posY = Math.floor(Math.random() * (this.span - 2));
  var speed = Math.floor(Math.random() * 5 + 1);
  console.log(speed)
  this.snakes.push(new Snake(id).setProp({
    direction: 'up',
    data: [{x: posX, y: posY}, {x: posX, y: posY + 1}, {x: posX, y: posY + 2}],
    speed: speed,
    revive: !!revive
  }));
  return this;
}

Grid.prototype.getSnake = function (id) {
  return this.snakes.filter(function (snake) {
    return snake.id === id;
  })[0];
}

Grid.prototype.getWarm = function () {
  return this.snakes.filter(function (snake) {
    return snake.id === 'warm';
  });
}

Grid.prototype.receiveMsg = function (id, msg) {
  var snake = this.getSnake(id);
  if (msg) {
    switch (msg) {
      case 'revive':
        if (!snake || snake.status !== true) {
          this.push(id, true);
        }
        break;
      case 'up':
      case 'down':
      case 'left':
      case 'right':
        if (snake && snake.status === true) {
          snake.setDirection(msg);
        }
        break;
    }
  }
  return this;
}

Grid.prototype.killSnake = function (id) {
  var snake = this.getSnake(id);
  if (snake) {
    snake.status = false;
  }
  return this;
}

Grid.prototype.clearDeadSnake = function () {
  this.snakes = this.snakes.filter(function (snake) {
    return snake.status !== false;
  });
  return this;
}

Grid.prototype.check = function () {
  var me = this;
  var lifeBook = {};
  this.snakes.forEach(function (snake) {
    // each other check
    if (snake.id === 'warm') {
      return;
    }
    snake.data.forEach(function (pos) {
      if (!lifeBook[pos.x + '' + pos.y]) {
        lifeBook[pos.x + '' + pos.y] = snake.id;
      } else {
        snake.status = false;
        me.killSnake(lifeBook[pos.x + '' + pos.y]);
      }
    });
  });
  return this;
}

module.exports = Grid;
